package com.kexio.auth.util;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.kexio.auth.context.TenantContextHolder;
import com.kexio.auth.dto.UserAuthInfo;

import cn.dev33.satoken.stp.StpUtil;

/**
 * 认证上下文工具类 - 统一API入口
 * 
 * 开发规范：
 * - 优先使用本类的静态方法
 * - 避免直接调用底层认证API
 * - 所有用户信息获取都通过此类
 * 
 * 设计目标：
 * - 统一API接口，避免开发者困惑
 * - 封装底层实现细节
 * - 提供更语义化的方法名
 * - 支持未来的扩展和迁移
 * 
 * 替代关系：
 * - 替代直接调用认证框架底层API
 * - 替代直接调用AuthContextUtils的静态方法
 * - 提供统一的认证信息获取入口
 * 
 * @author Kexio Team
 * @since 2.0.0
 */
@Component
public class AuthContextUtils {
    
    private static final Logger logger = LoggerFactory.getLogger(AuthContextUtils.class);
    
    /**
     * 获取当前用户ID
     * 
     * 推荐API，统一的用户ID获取入口
     * 
     * @return 当前用户ID，如果未登录则返回null
     */
    public static String getCurrentUserId() {
        try {
            if (!StpUtil.isLogin()) {
                return null;
            }
            
            // Sa-Token 存储的是复合ID格式: tenantId:userId
            String loginId = StpUtil.getLoginIdAsString();
            if (loginId.contains(":")) {
                String[] parts = loginId.split(":", 2);
                return parts.length > 1 ? parts[1] : parts[0];
            }
            return loginId;
        } catch (Exception e) {
            return null;
        }
    }
    
    /**
     * 获取当前用户名
     * 
     * @return 当前用户名，如果未登录则返回null
     */
    public static String getCurrentUsername() {
        UserAuthInfo user = getCurrentUser();
        return user != null ? user.getUsername() : null;
    }
    
    /**
     * 获取当前租户ID
     * 
     * 优先从ThreadLocal获取（由Filter设置），如果没有则从Session读取
     * 
     * @return 当前租户ID，如果租户功能关闭或未设置则返回null
     */
    public static String getCurrentTenantId() {
        try {
            // 优先从ThreadLocal获取（性能更好，已由Filter设置）
            String tenantId = TenantContextHolder.getCurrentTenantId();
            if (tenantId != null) {
                return tenantId;
            }
            
            // ThreadLocal为空时，从Session读取（降级方案）
            if (StpUtil.isLogin() && StpUtil.getSession().has("tenantId")) {
                return (String) StpUtil.getSession().get("tenantId");
            }
            
            return null;
        } catch (Exception e) {
            logger.warn("获取当前租户ID失败: {}", e.getMessage());
            return null;
        }
    }
    
    /**
     * 检查是否已认证
     * 
     * 推荐API，统一的认证状态检查入口
     * 
     * @return true表示用户已认证，false表示未认证
     */
    public static boolean isAuthenticated() {
        try {
            return StpUtil.isLogin();
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 检查当前用户是否有指定权限
     * 
     * 细粒度权限检查，支持复杂权限表达式
     * 
     * @param permission 权限码，如："user:list", "admin:config"
     * @return true表示有权限，false表示无权限或未登录
     */
    public static boolean hasPermission(String permission) {
        try {
            return StpUtil.hasPermission(permission);
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 检查当前用户是否有任意一个指定权限
     * 
     * @param permissions 权限码列表
     * @return true表示至少有一个权限，false表示都没有或未登录
     */
    public static boolean hasAnyPermission(String... permissions) {
        if (permissions == null || permissions.length == 0) {
            return false;
        }
        
        for (String permission : permissions) {
            if (hasPermission(permission)) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * 检查当前用户是否有所有指定权限
     * 
     * @param permissions 权限码列表
     * @return true表示拥有所有权限，false表示缺少至少一个权限或未登录
     */
    public static boolean hasAllPermissions(String... permissions) {
        if (permissions == null || permissions.length == 0) {
            return true;
        }
        
        for (String permission : permissions) {
            if (!hasPermission(permission)) {
                return false;
            }
        }
        return true;
    }
    
    /**
     * 检查当前用户是否有指定角色
     * 
     * @param roleCode 角色代码，如："ADMIN", "USER"
     * @return true表示有角色，false表示无角色或未登录
     */
    public static boolean hasRole(String roleCode) {
        try {
            return StpUtil.hasRole(roleCode);
        } catch (Exception e) {
            return false;
        }
    }
    
    /**
     * 获取完整的用户认证信息
     * 
     * 提供完整的用户信息，包括权限、角色、租户等
     * 
     * @return 用户认证信息对象，如果未登录则返回null
     */
    public static UserAuthInfo getCurrentUser() {
        try {
            if (!StpUtil.isLogin()) {
                logger.debug("用户未登录");
                return null;
            }
            
            // 从 Sa-Token Session 获取用户信息
            try {
                UserAuthInfo userInfo = (UserAuthInfo) StpUtil.getSession().get("userInfo");
                if (userInfo == null) {
                    logger.warn("Session中没有找到userInfo，sessionId={}", StpUtil.getSession().getId());
                }
                
                return userInfo;
            } catch (ClassCastException e) {
                logger.error("DevTools类加载器冲突 - 清理Session强制重新登录: {}", e.getMessage());
                
                // 清理当前Session，强制重新登录
                try {
                    StpUtil.getSession().clear();
                    StpUtil.logout();
                    logger.info("已清理Session，用户需要重新登录");
                } catch (Exception clearException) {
                    logger.error("清理Session失败: {}", clearException.getMessage());
                }
                
                return null;
            }
        } catch (Exception e) {
            logger.error("获取用户信息异常", e);
            return null;
        }
    }
    
    /**
     * 获取当前用户部门ID
     * 
     * @return 当前用户部门ID，如果未设置则返回null
     */
    public static String getCurrentUserDeptId() {
        UserAuthInfo user = getCurrentUser();
        return user != null ? user.getDeptId() : null;
    }
    
    /**
     * 检查当前用户是否为超级管理员
     * 
     * 超级管理员拥有所有权限，跨租户访问能力
     * 
     * @return true表示是超级管理员，false表示不是或未登录
     */
    public static boolean isSuperAdmin() {
        UserAuthInfo user = getCurrentUser();
        return user != null && user.isSuperAdmin();
    }
    
    /**
     * 检查当前用户是否有效（未禁用且未锁定）
     * 
     * @return true表示用户有效，false表示已禁用/锁定或未登录
     */
    public static boolean isCurrentUserValid() {
        UserAuthInfo user = getCurrentUser();
        return user != null && user.isValid();
    }
    
    /**
     * 获取客户端IP地址
     * 
     * 获取真实的客户端IP，考虑代理和负载均衡
     * 
     * @return 客户端IP地址
     */
    public static String getClientIp() {
        try {
            // 从 Sa-Token Session 获取客户端IP
            return (String) StpUtil.getSession().get("clientIp");
        } catch (Exception e) {
            return "unknown";
        }
    }
    
    /**
     * 获取当前请求的跟踪ID
     * 
     * 用于日志跟踪和问题排查
     * 
     * @return 跟踪ID
     */
    public static String getTraceId() {
        try {
            // 从 Sa-Token Session 获取跟踪ID
            return (String) StpUtil.getSession().get("traceId");
        } catch (Exception e) {
            return "unknown";
        }
    }
    
    /**
     * 断言当前用户已认证
     * 
     * 如果未认证会抛出异常
     * 
     * @throws IllegalStateException 如果用户未认证
     */
    public static void requireAuthenticated() {
        if (!isAuthenticated()) {
            throw new IllegalStateException("用户未认证，请先登录");
        }
    }
    
    /**
     * 断言当前用户拥有指定权限
     * 
     * 如果无权限会抛出异常
     * 
     * @param permission 需要的权限码
     * @throws IllegalStateException 如果无权限
     */
    public static void requirePermission(String permission) {
        requireAuthenticated();
        if (!hasPermission(permission)) {
            throw new IllegalStateException("权限不足，需要权限: " + permission);
        }
    }
    
    /**
     * 断言当前用户是超级管理员
     * 
     * 如果不是超级管理员会抛出异常
     * 
     * @throws IllegalStateException 如果不是超级管理员
     */
    public static void requireSuperAdmin() {
        requireAuthenticated();
        if (!isSuperAdmin()) {
            throw new IllegalStateException("需要超级管理员权限");
        }
    }
    
    // ==================== 上下文摘要信息 ====================
    
    /**
     * 获取上下文信息摘要（用于日志和调试）
     * 
     * 格式：AuthContext{userId=admin, tenantId=default, permissions=86, roles=1}
     * 
     * @return 上下文摘要字符串
     */
    public static String getContextSummary() {
        try {
            if (!StpUtil.isLogin()) {
                return "AuthContext{user=anonymous}";
            }
            
            UserAuthInfo user = getCurrentUser();
            StringBuilder summary = new StringBuilder();
            summary.append("AuthContext{");
            
            if (user != null) {
                summary.append("userId=").append(user.getUserId())
                       .append(", username=").append(user.getUsername())
                       .append(", tenantId=").append(user.getTenantId());
                       
                if (user.getPermissions() != null) {
                    summary.append(", permissions=").append(user.getPermissions().size());
                }
                if (user.getRoles() != null) {
                    summary.append(", roles=").append(user.getRoles().size());
                }
            } else {
                summary.append("user=loginButNoUserInfo");
            }
            
            summary.append("}");
            return summary.toString();
        } catch (Exception e) {
            return "AuthContext{error=" + e.getMessage() + "}";
        }
    }
    
    /**
     * 检查上下文是否完整
     * 
     * 完整的上下文包括：用户信息、租户信息、跟踪ID
     * 
     * @return true表示上下文完整，false表示缺少关键信息
     */
    public static boolean isContextComplete() {
        try {
            return isAuthenticated() && 
                   getCurrentUser() != null && 
                   getCurrentUser().isValid();
        } catch (Exception e) {
            return false;
        }
    }
    
}
